package com.p2p.auth.controller.api.crm;

import com.p2p.auth.common.base.JsonResult;
import com.p2p.auth.common.base.ProcessAPI;
import com.p2p.auth.common.enums.AuthMenuType;
import com.p2p.auth.exceptions.ValidateException;
import com.p2p.auth.controller.Routes;
import com.p2p.auth.domain.entity.AuthMenuItem;
import com.p2p.auth.domain.entity.RoleAssignMenu;
import com.p2p.auth.service.lifeCycle.AuthMenuItemFactory;
import com.p2p.auth.service.repository.AuthMenuItemRepository;
import com.p2p.auth.service.repository.RoleAssignMenuRepository;
import com.p2p.auth.domain.dto.auth.AuthMenuItemDTO;
import com.p2p.auth.domain.dto.auth.RoleAssignMenuDTO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Created by Antinomy on 17/7/26.
 */
@RestController
@Api(value = "权限菜单模块", description = "权限菜单模块")
public class CrmAuthMenuController {

    @Autowired
    private AuthMenuItemRepository authMenuItemRepo;

    @Autowired
    private RoleAssignMenuRepository roleAssignMenuRepo;


    @ApiOperation(value = "创建权限菜单", notes = "输入权限菜单基本信息", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ApiImplicitParam(name = "dto", value = "权限菜单基本信息", required = true, dataType = "AuthMenuItemDTO")
    @RequestMapping(value = Routes.CRM_AUTH_MENU, method = RequestMethod.POST)
    @ResponseBody
    public JsonResult create(HttpServletRequest request, @RequestBody AuthMenuItemDTO dto) {

        ProcessAPI api = (jsonResult, validate) -> {
            validate.check("label", dto.getLabel());

            AuthMenuItem menuItem = AuthMenuItemFactory.createFromDTO(dto);


            menuItem = authMenuItemRepo.saveAndFlush(menuItem);

            jsonResult.result = menuItem;
            jsonResult.size = 1L;
        };

        return api.process(request);
    }

    @ApiOperation(value = "读取所有权限菜单", notes = "读取所有权限菜单", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @RequestMapping(value = Routes.CRM_AUTH_MENU, method = RequestMethod.GET)
    @ResponseBody
    public JsonResult getAll(HttpServletRequest request) {

        ProcessAPI api = (jsonResult, validate) -> {
            List<AuthMenuItemDTO> root = new ArrayList<>();

            List<AuthMenuItem> menuLv1s = authMenuItemRepo.findByMenuType(AuthMenuType.MENU_LV1);

            for (AuthMenuItem lv1 : menuLv1s) {
                AuthMenuItemDTO lv1DTO = AuthMenuItemFactory.createFromEntity(lv1);

                List<AuthMenuItem> menuLv2s = authMenuItemRepo.findByMenuTypeAndParentId(AuthMenuType.MENU_LV2, lv1.getId());

                List<AuthMenuItemDTO> lv2sDTO = new ArrayList<>();
                if (menuLv2s != null && menuLv2s.size() > 0) {
                    for (AuthMenuItem lv2 : menuLv2s) {
                        AuthMenuItemDTO lv2DTO = AuthMenuItemFactory.createFromEntity(lv2);

                        List<AuthMenuItem> buttons = authMenuItemRepo.findByMenuTypeAndParentId(AuthMenuType.BUTTON, lv2.getId());

                        List<AuthMenuItemDTO> buttonsDTO = new ArrayList<>();
                        for (AuthMenuItem button : buttons) {
                            AuthMenuItemDTO buttonDTO = AuthMenuItemFactory.createFromEntity(button);
                            buttonsDTO.add(buttonDTO);
                        }

                        lv2DTO.setChildren(buttonsDTO);
                        lv2sDTO.add(lv2DTO);
                    }
                }
                lv1DTO.setChildren(lv2sDTO);
                root.add(lv1DTO);
            }

            jsonResult.result = root;
            jsonResult.size = (long) root.size();
        };

        return api.process(request);

    }

    @ApiOperation(value = "角色分配菜单", notes = "角色分配菜单", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "dto", value = "角色分配菜单参数", required = true, dataType = "RoleAssignMenuDTO")
    })
    @RequestMapping(value = Routes.CRM_ROLE_ASSIGN_MENU, method = RequestMethod.POST)
    @ResponseBody
    @Transactional
    public JsonResult roleAssignMenus(HttpServletRequest request, @RequestBody RoleAssignMenuDTO dto) {

        ProcessAPI api = (jsonResult, validate) -> {
            String roleId = dto.getRoleId();
            validate.check("roleId", roleId);
            List<String> menuItemDTOs = dto.getMenuIds();
            validate.check("menus", menuItemDTOs);

            if(menuItemDTOs.size() <= 0) {
                throw new ValidateException("请选择菜单");
            }
            HashMap<Long,AuthMenuItem> authMenuItems = new HashMap<>();

            menuItemDTOs
                    .parallelStream()
                    .forEach(menuId -> {
                        AuthMenuItem menuItem = authMenuItemRepo.findByMenuId(menuId);

                        if (menuItem == null) {
                            throw new ValidateException("请选择有效菜单Id:" + menuId);
                        }
                        authMenuItems.put(menuItem.getId(), menuItem);

                        addParent(authMenuItems, menuItem.getParentId());
                    });


            roleAssignMenuRepo.deleteByRoleId(roleId);

            authMenuItems
                    .entrySet()
                    .parallelStream()
                    .forEach(eachMap -> {
                        AuthMenuItem item = eachMap.getValue();
                        RoleAssignMenu roleAssignMenu = new RoleAssignMenu();
                        roleAssignMenu.setRoleId(roleId);
                        roleAssignMenu.setMenuId(item.getMenuId());
                        roleAssignMenu.setMenuType(item.getMenuType());
                        roleAssignMenu.setParentId(item.getParentId());
                        roleAssignMenu.setUniqueId(item.getUniqueId());
                        roleAssignMenuRepo.saveAndFlush(roleAssignMenu);
                    });


            jsonResult.result = authMenuItems;
            jsonResult.size = (long)authMenuItems.size();
        };

        return api.process(request);

    }

    private void addParent(HashMap<Long, AuthMenuItem> authMenuItems, String  parentId) {
        if (parentId == null) {
            return;
        }

        AuthMenuItem parent = authMenuItemRepo.findByMenuId(parentId);

        if (parent == null) {
            return;
        }

        if (authMenuItems.get(parent.getId()) != null) {
            return;
        }
        authMenuItems.put(parent.getId(), parent);

        if (parent.getParentId() == null) {
            return;
        }

        if (parent.getMenuType().equals(AuthMenuType.MENU_LV1)) {
            return;
        }

        addParent(authMenuItems, parent.getParentId());
    }

    @ApiOperation(value = "读取某一个角色下的权限菜单", notes = "读取某一个角色下的权限菜单", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ApiImplicitParam(name = "roleId", value = "角色Id", required = true, dataType = "Long", paramType = "query")
    @RequestMapping(value = Routes.CRM_AUTH_MENU_ROLE, method = RequestMethod.GET)
    @ResponseBody
    public JsonResult getByRole(HttpServletRequest request, @RequestParam String roleId) {

        ProcessAPI api = (jsonResult, validate) -> {

            validate.check("roleId", roleId);

            List<AuthMenuItemDTO> root = new ArrayList<>();

            List<RoleAssignMenu> menuLv1s = roleAssignMenuRepo.findByMenuTypeAndRoleId(AuthMenuType.MENU_LV1, roleId);

            for (RoleAssignMenu roleAssignMenu : menuLv1s) {
                AuthMenuItem lv1 = authMenuItemRepo.findByMenuId(roleAssignMenu.getMenuId());

                AuthMenuItemDTO lv1DTO = AuthMenuItemFactory.createFromEntity(lv1);

                String rootUniqueId = lv1.getUniqueId();
                lv1DTO.setRootUniqueId(rootUniqueId);
                List<RoleAssignMenu> menuLv2s = roleAssignMenuRepo.findByMenuTypeAndRoleIdAndParentId(AuthMenuType.MENU_LV2, roleId, lv1.getParentId());

                List<AuthMenuItemDTO> lv2sDTO = new ArrayList<>();
                if (menuLv2s != null && menuLv2s.size() > 0) {
                    for (RoleAssignMenu roleAssignMenuLv2  : menuLv2s) {
                        AuthMenuItem lv2 = authMenuItemRepo.findByMenuId(roleAssignMenuLv2.getMenuId());
                        AuthMenuItemDTO lv2DTO = AuthMenuItemFactory.createFromEntity(lv2);
                        lv2DTO.setRootUniqueId(rootUniqueId);

                        List<RoleAssignMenu> buttons = roleAssignMenuRepo.findByMenuTypeAndRoleIdAndParentId(AuthMenuType.BUTTON, roleId, lv2.getParentId());

                        List<String> buttonsDTO = new ArrayList<>();
                        for (RoleAssignMenu roleAssignMenuLv3 : buttons) {
                            AuthMenuItem button = authMenuItemRepo.findByMenuId(roleAssignMenuLv3.getMenuId());
                            buttonsDTO.add(button.getRouter());
                        }

                        lv2DTO.setButtons(buttonsDTO);
                        lv2sDTO.add(lv2DTO);
                    }
                }
                lv1DTO.setChildren(lv2sDTO);
                root.add(lv1DTO);
            }

            jsonResult.result = root;
            jsonResult.size = (long) root.size();
        };

        return api.process(request);

    }



    @ApiOperation(value = "读取角色的权限菜单Id", notes = "读取角色的权限菜单Id", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ApiImplicitParam(name = "roleId", value = "角色Id", required = true, dataType = "Long", paramType = "query")
    @RequestMapping(value = Routes.CRM_AUTH_MENU_ROLE_IDS, method = RequestMethod.GET)
    @ResponseBody
    public JsonResult getByRoleIS(HttpServletRequest request, @RequestParam String roleId) {

        ProcessAPI api = (jsonResult, validate) -> {

            validate.check("roleId", roleId);

            List<String> roleIds = roleAssignMenuRepo.findByMenuTypeAndRoleId(AuthMenuType.BUTTON,roleId)
                    .parallelStream()
                    .map(RoleAssignMenu::getMenuId)
                    .collect(Collectors.toList());

            jsonResult.result = roleIds;
            jsonResult.size = (long) roleIds.size();
        };

        return api.process(request);
    }
}
